﻿//==============================================================================
// File: AssociationSync.cs
// Created: 2010-05-10
// Author: Piotr Włodek
//==============================================================================
// This file is a part of MAMMOTH project.
// Copyright (C) 2010 AGH University of Science and Technology, Krakow.
// https://caribou.iisg.agh.edu.pl/trac/mammoth
//
// Mammoth is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// Mammoth is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public License
// along with WpfRcp. If not, see http://www.gnu.org/licenses/.
//==============================================================================

using System;
using System.Collections.Generic;
using System.ComponentModel;
using WpfRcp.PropertyModel.Core;
using WpfRcp.PropertyModel.Scope;

namespace WpfRcp.PropertyModel
{
    /// <summary>
    /// Represents a <see cref="IPropertyContainer"/> which delegates all calls
    /// to the other <see cref="IPropertyContainer"/> instance.
    /// </summary>
    [Serializable]
    public abstract class DelegatePropertyContainer : IPropertyContainer, IEditableObject
    {
        private IPropertyContainer m_Container;

        protected DelegatePropertyContainer()
        {
            // ReSharper disable DoNotCallOverridableMethodsInConstructor
            
            Container = CreatePropertyContainer();
            Container.Validate();

            // ReSharper restore DoNotCallOverridableMethodsInConstructor
        }

        protected IPropertyContainer Container
        {
            get { return m_Container; }
            set { m_Container = value; }
        }

        protected abstract IPropertyContainer CreatePropertyContainer();

        #region Implementation of IDynamicPropertyRegistry

        public MetaProperty RegisterDynamic(string name, Type propertyType)
        {
            return m_Container.RegisterDynamic(name, propertyType);
        }

        public MetaProperty RegisterDynamic(string name, Type propertyType, PropertyMetadata metadata)
        {
            return m_Container.RegisterDynamic(name, propertyType, metadata);
        }

        public void UnregisterDynamic(MetaProperty metaProperty)
        {
            m_Container.UnregisterDynamic(metaProperty);
        }

        public void UnregisterDynamic(string name)
        {
            m_Container.UnregisterDynamic(name);
        }

        public MetaPropertyCollection GetDynamicProperties()
        {
            return m_Container.GetDynamicProperties();
        }

        #endregion

        #region Implementation of IValidatable

        public bool IsValid
        {
            get { return m_Container.IsValid; }
        }

        #endregion

        #region Implementation of INotifyObjectStateChanged

        event EventHandler<EventArgs> INotifyObjectStateChanged.ObjectStateChanged
        {
            add { m_Container.ObjectStateChanged += value; }
            remove { m_Container.ObjectStateChanged -= value; }
        }

        #endregion

        #region Implementation of IPropertyContainer

        public PropertyContainerType PropertyContainerType
        {
            get { return m_Container.PropertyContainerType; }
        }

        object IPropertyContainer.this[MetaProperty index]
        {
            get { return m_Container[index]; }
            set { m_Container[index] = value; }
        }

        object IPropertyContainer.this[string index]
        {
            get { return m_Container[index]; }
            set { m_Container[index] = value; }
        }

        public object GetValue(MetaProperty property)
        {
            return m_Container.GetValue(property);
        }

        public object GetValue(string property)
        {
            return m_Container.GetValue(property);
        }

        public void SetValue(string property, object value)
        {
            m_Container.SetValue(property, value);
        }

        public void SetValue(MetaProperty metaProperty, object value)
        {
            m_Container.SetValue(metaProperty, value);
        }

        public void SetValue(MetaPropertyKey propertyKey, object value)
        {
            m_Container.SetValue(propertyKey, value);
        }

        public void ClearValue(MetaProperty metaProperty)
        {
            m_Container.ClearValue(metaProperty);
        }

        public void ClearValue(string property)
        {
            m_Container.ClearValue(property);
        }

        public bool HasDefaultValue(MetaProperty metaProperty)
        {
            return m_Container.HasDefaultValue(metaProperty);
        }

        public bool HasDefaultValue(string propertyName)
        {
            return m_Container.HasDefaultValue(propertyName);
        }

        public bool HasValidValue(string property)
        {
            return m_Container.HasValidValue(property);
        }

        public bool HasValidValue(MetaProperty metaProperty)
        {
            return m_Container.HasDefaultValue(metaProperty);
        }

        public void ValidateProperty(MetaProperty metaProperty)
        {
            m_Container.ValidateProperty(metaProperty);
        }

        public void Validate()
        {
            m_Container.Validate();
        }

        public MetaPropertyCollection GetProperties()
        {
            return m_Container.GetProperties();
        }

        public MetaProperty GetProperty(string name)
        {
            return m_Container.GetProperty(name);
        }

        public IPropertyScope AddScope(IPropertyScope scope)
        {
            return m_Container.AddScope(scope);
        }

        public void RemoveScope(IPropertyScope scope)
        {
            m_Container.RemoveScope(scope);
        }

        public bool ContentEquals(IPropertyContainer compareTarget)
        {
            return m_Container.ContentEquals(compareTarget);
        }

        public bool ContentEquals(IPropertyContainer compareTarget, params string[] propertyNames)
        {
            return m_Container.ContentEquals(compareTarget, propertyNames);
        }

        public bool ContentEquals(IPropertyContainer compareTarget, IEnumerable<string> propertyNames)
        {
            return m_Container.ContentEquals(compareTarget, propertyNames);
        }

        public TInterface GetDuck<TInterface>() where TInterface : class
        {
            return m_Container.GetDuck<TInterface>();
        }

        #endregion

        #region Implementation of IEditableObject

        protected virtual void OnBeginEdit()
        {
            var editableObject = Container as IEditableObject;
            if (editableObject != null)
            {
                editableObject.BeginEdit();
            }
        }

        protected virtual void OnEndEdit()
        {
            var editableObject = Container as IEditableObject;
            if (editableObject != null)
            {
                editableObject.EndEdit();
            }
        }

        protected virtual void OnCancelEdit()
        {
            var editableObject = Container as IEditableObject;
            if (editableObject != null)
            {
                editableObject.CancelEdit();
            }
        }

        void IEditableObject.BeginEdit()
        {
            OnBeginEdit();
        }

        void IEditableObject.EndEdit()
        {
            OnEndEdit();
        }

        void IEditableObject.CancelEdit()
        {
            OnCancelEdit();
        }

        #endregion
    }
}